// FileDirItem
import 'dart:io';
import 'package:path/path.dart';
import 'package:property_change_notifier/property_change_notifier.dart';

class FileDirItem {
  String _path;
  String? _name;
  bool? _is_dir;
  List<FileDirItem> _children = [];

  FileDirItem(this._path) {
    //print('FileDirItem $_path');

    File file = File(_path);
    _name = basename(file.path);

    _is_dir = FileSystemEntity.isDirectorySync(_path);
    if (_is_dir == true) {
      var dir = Directory(_path);
      final List<FileSystemEntity> entities = dir.listSync().toList();
      final Iterable<File> files = entities.whereType<File>();
      final Iterable<Directory> dirs = entities.whereType<Directory>();

      for (var dir_t in dirs) {
        _children.add(FileDirItem(dir_t.path));
      }

      for (var file_t in files) {
        _children.add(FileDirItem(file_t.path));
      }
    }
  }

  String get path => _path;
  String get name => _name ?? '';
  List<FileDirItem> get children => _children;
}

class FileContent {
  late String _path;
  late String _content;

  FileContent(this._path) : _content = File(_path).readAsStringSync();

  String get content => _content;
  void update(content) => _content = content;

  void save() {
    File(_path).writeAsStringSync(_content);
  }
}

class FileList with PropertyChangeNotifier<String> {
  FileDirItem? _root;
  // last opened file
  String? _new_open_file;
  // all opened files
  List<String> _open_files = [];
  // current activate file
  String? _current_file;
  // map file to content
  Map<String, FileContent> _file_2_content = {};
  // current select file
  String? _select_file;

  static FileList? _instance;

  FileList._internal();
  static FileList getInstance() => _instance ??= FileList._internal();

  FileDirItem? get root => _root;
  String? get open_file_path => _new_open_file;
  String? get open_file_name =>
      _new_open_file == null ? null : basename(File(_new_open_file!).path);
  String? get current_file => _current_file;
  int get current_file_index =>
      _current_file == null ? 0 : _open_files.indexOf(_current_file!);
  List<String> get open_files => _open_files;

  String? get_file_content_by_file(String file) {
    return _file_2_content[file]?.content;
  }

  String? get_file_content_by_index(int index) {
    if (index < 0 || index >= _open_files.length) {
      return null;
    }

    String file = _open_files[index];
    return _file_2_content[file]?.content;
  }

  String? get_file_name(String file) {
    return basename(File(file).path);
  }

  void init(String path) {
    print('Hello to init $path');
    _root = FileDirItem(path);
    notifyListeners('root_change');
  }

  void open(String file) {
    var is_dir = FileSystemEntity.isDirectorySync(file);
    print('open file: $file $is_dir');
    _select_file = file;
    if (is_dir == true) {
      return;
    }

    if (_open_files.any((element) => file == element)) {
      select_current_file(_open_files.indexOf(file));
      return;
    }

    opened(file);
  }

  void opened(String file) {
    _open_files.add(file);
    _current_file = file;
    _file_2_content[file] = FileContent(file);

    notifyListeners('opened_file');
  }

  void closed(String file) {
    int index = _open_files.indexOf(file);
    closed_by_index(index);
  }

  void closed_by_index(int index) {
    if (index < 0) {
      return;
    }

    String file = _open_files[index];
    _file_2_content.remove(file);

    _open_files.removeAt(index);
    if (index >= _open_files.length) {
      index = _open_files.length - 1;
    }
    if (index >= 0 && index < _open_files.length) {
      _current_file = _open_files[index];
    } else {
      _current_file = null;
    }

    notifyListeners('closed_file');
  }

  void update_content(int index, String content) {
    if (index < 0 || index >= _open_files.length) {
      return;
    }

    String file = _open_files[index];
    _file_2_content[file]?.update(content);
  }

  void save_current_file() {
    if (_current_file == null) {
      return;
    }
    _file_2_content[_current_file]?.save();
  }

  void save_all_file() {
    _file_2_content.forEach((key, value) {
      value.save();
    });
  }

  void select_current_file(int index) {
    _current_file = _open_files[index];
    notifyListeners('current_index_change');
  }

  String? _current_select_directory() {
    if (_select_file == null) {
      return _root?.path;
    }
    var is_dir = FileSystemEntity.isDirectorySync(_select_file!);
    if (is_dir) {
      return _select_file;
    }

    return Directory(_select_file!).parent.path;
  }

  void new_file(String name) {
    String s_path = _current_select_directory() ?? '';
    String s_new_file = s_path + '/' + name;
    if (s_path == '') {
      return;
    }

    File f = File(s_new_file);
    f.createSync();
    init((_root?.path)!);
  }

  void new_dir(String name) {
    String s_path = _current_select_directory() ?? '';
    String s_new_file = s_path + '/' + name;
    if (s_path == '') {
      return;
    }

    Directory(s_new_file).createSync(recursive: true);
    init((_root?.path)!);
  }
}
